home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume24 / gnudiff1.15 / part06 < prev    next >
Encoding:
Internet Message Format  |  1991-03-05  |  40.0 KB

  1. Subject:  v24i021:  GNU Diff, version 1.15, Part06/08
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: 20d4cb87 53dcbca3 10725bbd b18999e6
  5.  
  6. Submitted-by: Paul Eggert <eggert@twinsun.com>
  7. Posting-number: Volume 24, Issue 21
  8. Archive-name: gnudiff1.15/part06
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then unpack
  12. # it by saving it into a file and typing "sh file".  To overwrite existing
  13. # files, type "sh file -c".  You can also feed this as standard input via
  14. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  15. # will see the following message at the end:
  16. #        "End of archive 6 (of 8)."
  17. # Contents:  regex.c2
  18. # Wrapped by eggert@ata on Mon Jan  7 11:25:31 1991
  19. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  20. if test -f 'regex.c2' -a "${1}" != "-c" ; then 
  21.   echo shar: Will not clobber existing file \"'regex.c2'\"
  22. else
  23. echo shar: Extracting \"'regex.c2'\" \(37881 characters\)
  24. sed "s/^X//" >'regex.c2' <<'END_OF_FILE'
  25. X
  26. X
  27. X
  28. X/* Like re_search_2, below, but only one string is specified, and
  29. X   doesn't let you say where to stop matching. */
  30. X
  31. Xint
  32. Xre_search (pbufp, string, size, startpos, range, regs)
  33. X     struct re_pattern_buffer *pbufp;
  34. X     char *string;
  35. X     int size, startpos, range;
  36. X     struct re_registers *regs;
  37. X{
  38. X  return re_search_2 (pbufp, (char *) 0, 0, string, size, startpos, range, 
  39. X              regs, size);
  40. X}
  41. X
  42. X
  43. X/* Using the compiled pattern in PBUFP->buffer, first tries to match the
  44. X   virtual concatenation of STRING1 and STRING2, starting first at index
  45. X   STARTPOS, then at STARTPOS + 1, and so on.  RANGE is the number of
  46. X   places to try before giving up.  If RANGE is negative, it searches
  47. X   backwards, i.e., the starting positions tried are STARTPOS, STARTPOS
  48. X   - 1, etc.  STRING1 and STRING2 are of SIZE1 and SIZE2, respectively.
  49. X   In REGS, return the indices of the virtual concatenation of STRING1
  50. X   and STRING2 that matched the entire PBUFP->buffer and its contained
  51. X   subexpressions.  Do not consider matching one past the index MSTOP in
  52. X   the virtual concatenation of STRING1 and STRING2.
  53. X
  54. X   The value returned is the position in the strings at which the match
  55. X   was found, or -1 if no match was found, or -2 if error (such as
  56. X   failure stack overflow).  */
  57. X
  58. Xint
  59. Xre_search_2 (pbufp, string1, size1, string2, size2, startpos, range,
  60. X         regs, mstop)
  61. X     struct re_pattern_buffer *pbufp;
  62. X     char *string1, *string2;
  63. X     int size1, size2;
  64. X     int startpos;
  65. X     register int range;
  66. X     struct re_registers *regs;
  67. X     int mstop;
  68. X{
  69. X  register char *fastmap = pbufp->fastmap;
  70. X  register unsigned char *translate = (unsigned char *) pbufp->translate;
  71. X  int total_size = size1 + size2;
  72. X  int endpos = startpos + range;
  73. X  int val;
  74. X
  75. X  /* Check for out-of-range starting position.  */
  76. X  if (startpos < 0  ||  startpos > total_size)
  77. X    return -1;
  78. X    
  79. X  /* Fix up range if it would eventually take startpos outside of the
  80. X     virtual concatenation of string1 and string2.  */
  81. X  if (endpos < -1)
  82. X    range = -1 - startpos;
  83. X  else if (endpos > total_size)
  84. X    range = total_size - startpos;
  85. X
  86. X  /* Update the fastmap now if not correct already.  */
  87. X  if (fastmap && !pbufp->fastmap_accurate)
  88. X    re_compile_fastmap (pbufp);
  89. X  
  90. X  /* If the search isn't to be a backwards one, don't waste time in a
  91. X     long search for a pattern that says it is anchored.  */
  92. X  if (pbufp->used > 0 && (enum regexpcode) pbufp->buffer[0] == begbuf
  93. X      && range > 0)
  94. X    {
  95. X      if (startpos > 0)
  96. X    return -1;
  97. X      else
  98. X    range = 1;
  99. X    }
  100. X
  101. X  while (1)
  102. X    { 
  103. X      /* If a fastmap is supplied, skip quickly over characters that
  104. X         cannot possibly be the start of a match.  Note, however, that
  105. X         if the pattern can possibly match the null string, we must
  106. X         test it at each starting point so that we take the first null
  107. X         string we get.  */
  108. X
  109. X      if (fastmap && startpos < total_size && pbufp->can_be_null != 1)
  110. X    {
  111. X      if (range > 0)    /* Searching forwards.  */
  112. X        {
  113. X          register int lim = 0;
  114. X          register unsigned char *p;
  115. X          int irange = range;
  116. X          if (startpos < size1 && startpos + range >= size1)
  117. X        lim = range - (size1 - startpos);
  118. X
  119. X          p = ((unsigned char *)
  120. X           &(startpos >= size1 ? string2 - size1 : string1)[startpos]);
  121. X
  122. X              while (range > lim && !fastmap[translate 
  123. X                                             ? translate[*p++]
  124. X                                             : *p++])
  125. X            range--;
  126. X          startpos += irange - range;
  127. X        }
  128. X      else                /* Searching backwards.  */
  129. X        {
  130. X          register unsigned char c;
  131. X
  132. X              if (string1 == 0 || startpos >= size1)
  133. X        c = string2[startpos - size1];
  134. X          else 
  135. X        c = string1[startpos];
  136. X
  137. X              c &= 0xff;
  138. X          if (translate ? !fastmap[translate[c]] : !fastmap[c])
  139. X        goto advance;
  140. X        }
  141. X    }
  142. X
  143. X      if (range >= 0 && startpos == total_size
  144. X      && fastmap && pbufp->can_be_null == 0)
  145. X    return -1;
  146. X
  147. X      val = re_match_2 (pbufp, string1, size1, string2, size2, startpos,
  148. X            regs, mstop);
  149. X      if (val >= 0)
  150. X    return startpos;
  151. X      if (val == -2)
  152. X    return -2;
  153. X
  154. X#ifdef C_ALLOCA
  155. X      alloca (0);
  156. X#endif /* C_ALLOCA */
  157. X
  158. X    advance:
  159. X      if (!range) 
  160. X        break;
  161. X      else if (range > 0) 
  162. X        {
  163. X          range--; 
  164. X          startpos++;
  165. X        }
  166. X      else
  167. X        {
  168. X          range++; 
  169. X          startpos--;
  170. X        }
  171. X    }
  172. X  return -1;
  173. X}
  174. X
  175. X
  176. X
  177. X#ifndef emacs   /* emacs never uses this.  */
  178. Xint
  179. Xre_match (pbufp, string, size, pos, regs)
  180. X     struct re_pattern_buffer *pbufp;
  181. X     char *string;
  182. X     int size, pos;
  183. X     struct re_registers *regs;
  184. X{
  185. X  return re_match_2 (pbufp, (char *) 0, 0, string, size, pos, regs, size); 
  186. X}
  187. X#endif /* not emacs */
  188. X
  189. X
  190. X/* The following are used for re_match_2, defined below:  */
  191. X
  192. X/* Roughly the maximum number of failure points on the stack.  Would be
  193. X   exactly that if always pushed MAX_NUM_FAILURE_ITEMS each time we failed.  */
  194. X   
  195. Xint re_max_failures = 2000;
  196. X
  197. X/* Routine used by re_match_2.  */
  198. Xstatic int bcmp_translate ();
  199. X
  200. X
  201. X/* Structure and accessing macros used in re_match_2:  */
  202. X
  203. Xstruct register_info
  204. X{
  205. X  unsigned is_active : 1;
  206. X  unsigned matched_something : 1;
  207. X};
  208. X
  209. X#define IS_ACTIVE(R)  ((R).is_active)
  210. X#define MATCHED_SOMETHING(R)  ((R).matched_something)
  211. X
  212. X
  213. X/* Macros used by re_match_2:  */
  214. X
  215. X
  216. X/* I.e., regstart, regend, and reg_info.  */
  217. X
  218. X#define NUM_REG_ITEMS  3
  219. X
  220. X/* We push at most this many things on the stack whenever we
  221. X   fail.  The `+ 2' refers to PATTERN_PLACE and STRING_PLACE, which are
  222. X   arguments to the PUSH_FAILURE_POINT macro.  */
  223. X
  224. X#define MAX_NUM_FAILURE_ITEMS   (RE_NREGS * NUM_REG_ITEMS + 2)
  225. X
  226. X
  227. X/* We push this many things on the stack whenever we fail.  */
  228. X
  229. X#define NUM_FAILURE_ITEMS  (last_used_reg * NUM_REG_ITEMS + 2)
  230. X
  231. X
  232. X/* This pushes most of the information about the current state we will want
  233. X   if we ever fail back to it.  */
  234. X
  235. X#define PUSH_FAILURE_POINT(pattern_place, string_place)            \
  236. X  {                                    \
  237. X    short last_used_reg, this_reg;                    \
  238. X                                    \
  239. X    /* Find out how many registers are active or have been matched.    \
  240. X       (Aside from register zero, which is only set at the end.)  */    \
  241. X    for (last_used_reg = RE_NREGS - 1; last_used_reg > 0; last_used_reg--)\
  242. X      if (regstart[last_used_reg] != (unsigned char *) -1)        \
  243. X        break;                                \
  244. X                                    \
  245. X    if (stacke - stackp < NUM_FAILURE_ITEMS)                \
  246. X      {                                    \
  247. X    unsigned char **stackx;                        \
  248. X    if (stacke - stackb > re_max_failures * MAX_NUM_FAILURE_ITEMS)    \
  249. X      return -2;                            \
  250. X                                    \
  251. X        /* Roughly double the size of the stack.  */            \
  252. X        stackx = (unsigned char **) alloca (2 * MAX_NUM_FAILURE_ITEMS    \
  253. X                            * (stacke - stackb)        \
  254. X                                            * sizeof (unsigned char *));\
  255. X    /* Only copy what is in use.  */                \
  256. X        bcopy (stackb, stackx, (stackp - stackb) * sizeof (char *));    \
  257. X    stackp = stackx + (stackp - stackb);                \
  258. X    stackb = stackx;                        \
  259. X    stacke = stackb + 2 * MAX_NUM_FAILURE_ITEMS * (stacke - stackb);\
  260. X      }                                    \
  261. X                                    \
  262. X    /* Now push the info for each of those registers.  */        \
  263. X    for (this_reg = 1; this_reg <= last_used_reg; this_reg++)        \
  264. X      {                                    \
  265. X        *stackp++ = regstart[this_reg];                    \
  266. X        *stackp++ = regend[this_reg];                    \
  267. X        *stackp++ = (unsigned char *) ®_info[this_reg];        \
  268. X      }                                    \
  269. X                                    \
  270. X    /* Push how many registers we saved.  */                \
  271. X    *stackp++ = (unsigned char *) last_used_reg;            \
  272. X                                    \
  273. X    *stackp++ = pattern_place;                                          \
  274. X    *stackp++ = string_place;                                           \
  275. X  }
  276. X  
  277. X
  278. X/* This pops what PUSH_FAILURE_POINT pushes.  */
  279. X
  280. X#define POP_FAILURE_POINT()                        \
  281. X  {                                    \
  282. X    int temp;                                \
  283. X    stackp -= 2;        /* Remove failure points.  */        \
  284. X    temp = (int) *--stackp;    /* How many regs pushed.  */            \
  285. X    temp *= NUM_REG_ITEMS;    /* How much to take off the stack.  */    \
  286. X    stackp -= temp;         /* Remove the register info.  */    \
  287. X  }
  288. X
  289. X
  290. X#define MATCHING_IN_FIRST_STRING  (dend == end_match_1)
  291. X
  292. X/* Is true if there is a first string and if PTR is pointing anywhere
  293. X   inside it or just past the end.  */
  294. X   
  295. X#define IS_IN_FIRST_STRING(ptr)                     \
  296. X    (size1 && string1 <= (ptr) && (ptr) <= string1 + size1)
  297. X
  298. X/* Call before fetching a character with *d.  This switches over to
  299. X   string2 if necessary.  */
  300. X
  301. X#define PREFETCH                            \
  302. X while (d == dend)                                \
  303. X  {                                    \
  304. X    /* end of string2 => fail.  */                    \
  305. X    if (dend == end_match_2)                         \
  306. X      goto fail;                            \
  307. X    /* end of string1 => advance to string2.  */             \
  308. X    d = string2;                                \
  309. X    dend = end_match_2;                            \
  310. X  }
  311. X
  312. X
  313. X/* Call this when have matched something; it sets `matched' flags for the
  314. X   registers corresponding to the subexpressions of which we currently
  315. X   are inside.  */
  316. X#define SET_REGS_MATCHED                         \
  317. X  { unsigned this_reg;                             \
  318. X    for (this_reg = 0; this_reg < RE_NREGS; this_reg++)         \
  319. X      {                                 \
  320. X        if (IS_ACTIVE(reg_info[this_reg]))                \
  321. X          MATCHED_SOMETHING(reg_info[this_reg]) = 1;            \
  322. X        else                                \
  323. X          MATCHED_SOMETHING(reg_info[this_reg]) = 0;            \
  324. X      }                                 \
  325. X  }
  326. X
  327. X/* Test if at very beginning or at very end of the virtual concatenation
  328. X   of string1 and string2.  If there is only one string, we've put it in
  329. X   string2.  */
  330. X
  331. X#define AT_STRINGS_BEG  (d == (size1 ? string1 : string2)  ||  !size2)
  332. X#define AT_STRINGS_END  (d == end2)    
  333. X
  334. X#define AT_WORD_BOUNDARY                        \
  335. X  (AT_STRINGS_BEG || AT_STRINGS_END || IS_A_LETTER (d - 1) != IS_A_LETTER (d))
  336. X
  337. X/* We have two special cases to check for: 
  338. X     1) if we're past the end of string1, we have to look at the first
  339. X        character in string2;
  340. X     2) if we're before the beginning of string2, we have to look at the
  341. X        last character in string1; we assume there is a string1, so use
  342. X        this in conjunction with AT_STRINGS_BEG.  */
  343. X#define IS_A_LETTER(d)                            \
  344. X  (SYNTAX ((d) == end1 ? *string2 : (d) == string2 - 1 ? *(end1 - 1) : *(d))\
  345. X   == Sword)
  346. X
  347. X
  348. X/* Match the pattern described by PBUFP against the virtual
  349. X   concatenation of STRING1 and STRING2, which are of SIZE1 and SIZE2,
  350. X   respectively.  Start the match at index POS in the virtual
  351. X   concatenation of STRING1 and STRING2.  In REGS, return the indices of
  352. X   the virtual concatenation of STRING1 and STRING2 that matched the
  353. X   entire PBUFP->buffer and its contained subexpressions.  Do not
  354. X   consider matching one past the index MSTOP in the virtual
  355. X   concatenation of STRING1 and STRING2.
  356. X
  357. X   If pbufp->fastmap is nonzero, then it had better be up to date.
  358. X
  359. X   The reason that the data to match are specified as two components
  360. X   which are to be regarded as concatenated is so this function can be
  361. X   used directly on the contents of an Emacs buffer.
  362. X
  363. X   -1 is returned if there is no match.  -2 is returned if there is an
  364. X   error (such as match stack overflow).  Otherwise the value is the
  365. X   length of the substring which was matched.  */
  366. X
  367. Xint
  368. Xre_match_2 (pbufp, string1_arg, size1, string2_arg, size2, pos, regs, mstop)
  369. X     struct re_pattern_buffer *pbufp;
  370. X     char *string1_arg, *string2_arg;
  371. X     int size1, size2;
  372. X     int pos;
  373. X     struct re_registers *regs;
  374. X     int mstop;
  375. X{
  376. X  register unsigned char *p = (unsigned char *) pbufp->buffer;
  377. X
  378. X  /* Pointer to beyond end of buffer.  */
  379. X  register unsigned char *pend = p + pbufp->used;
  380. X
  381. X  unsigned char *string1 = (unsigned char *) string1_arg;
  382. X  unsigned char *string2 = (unsigned char *) string2_arg;
  383. X  unsigned char *end1;        /* Just past end of first string.  */
  384. X  unsigned char *end2;        /* Just past end of second string.  */
  385. X
  386. X  /* Pointers into string1 and string2, just past the last characters in
  387. X     each to consider matching.  */
  388. X  unsigned char *end_match_1, *end_match_2;
  389. X
  390. X  register unsigned char *d, *dend;
  391. X  register int mcnt;            /* Multipurpose.  */
  392. X  unsigned char *translate = (unsigned char *) pbufp->translate;
  393. X  unsigned is_a_jump_n = 0;
  394. X
  395. X /* Failure point stack.  Each place that can handle a failure further
  396. X    down the line pushes a failure point on this stack.  It consists of
  397. X    restart, regend, and reg_info for all registers corresponding to the
  398. X    subexpressions we're currently inside, plus the number of such
  399. X    registers, and, finally, two char *'s.  The first char * is where to
  400. X    resume scanning the pattern; the second one is where to resume
  401. X    scanning the strings.  If the latter is zero, the failure point is a
  402. X    ``dummy''; if a failure happens and the failure point is a dummy, it
  403. X    gets discarded and the next next one is tried.  */
  404. X
  405. X  unsigned char *initial_stack[MAX_NUM_FAILURE_ITEMS * NFAILURES];
  406. X  unsigned char **stackb = initial_stack;
  407. X  unsigned char **stackp = stackb;
  408. X  unsigned char **stacke = &stackb[MAX_NUM_FAILURE_ITEMS * NFAILURES];
  409. X
  410. X
  411. X  /* Information on the contents of registers. These are pointers into
  412. X     the input strings; they record just what was matched (on this
  413. X     attempt) by a subexpression part of the pattern, that is, the
  414. X     regnum-th regstart pointer points to where in the pattern we began
  415. X     matching and the regnum-th regend points to right after where we
  416. X     stopped matching the regnum-th subexpression.  (The zeroth register
  417. X     keeps track of what the whole pattern matches.)  */
  418. X     
  419. X  unsigned char *regstart[RE_NREGS];
  420. X  unsigned char *regend[RE_NREGS];
  421. X
  422. X  /* The is_active field of reg_info helps us keep track of which (possibly
  423. X     nested) subexpressions we are currently in. The matched_something
  424. X     field of reg_info[reg_num] helps us tell whether or not we have
  425. X     matched any of the pattern so far this time through the reg_num-th
  426. X     subexpression.  These two fields get reset each time through any
  427. X     loop their register is in.  */
  428. X
  429. X  struct register_info reg_info[RE_NREGS];
  430. X
  431. X
  432. X  /* The following record the register info as found in the above
  433. X     variables when we find a match better than any we've seen before. 
  434. X     This happens as we backtrack through the failure points, which in
  435. X     turn happens only if we have not yet matched the entire string.  */
  436. X
  437. X  unsigned best_regs_set = 0;
  438. X  unsigned char *best_regstart[RE_NREGS];
  439. X  unsigned char *best_regend[RE_NREGS];
  440. X
  441. X
  442. X  /* Initialize subexpression text positions to -1 to mark ones that no
  443. X     \( or ( and \) or ) has been seen for. Also set all registers to
  444. X     inactive and mark them as not having matched anything or ever
  445. X     failed.  */
  446. X  for (mcnt = 0; mcnt < RE_NREGS; mcnt++)
  447. X    {
  448. X      regstart[mcnt] = regend[mcnt] = (unsigned char *) -1;
  449. X      IS_ACTIVE (reg_info[mcnt]) = 0;
  450. X      MATCHED_SOMETHING (reg_info[mcnt]) = 0;
  451. X    }
  452. X  
  453. X  if (regs)
  454. X    for (mcnt = 0; mcnt < RE_NREGS; mcnt++)
  455. X      regs->start[mcnt] = regs->end[mcnt] = -1;
  456. X
  457. X  /* Set up pointers to ends of strings.
  458. X     Don't allow the second string to be empty unless both are empty.  */
  459. X  if (size2 == 0)
  460. X    {
  461. X      string2 = string1;
  462. X      size2 = size1;
  463. X      string1 = 0;
  464. X      size1 = 0;
  465. X    }
  466. X  end1 = string1 + size1;
  467. X  end2 = string2 + size2;
  468. X
  469. X  /* Compute where to stop matching, within the two strings.  */
  470. X  if (mstop <= size1)
  471. X    {
  472. X      end_match_1 = string1 + mstop;
  473. X      end_match_2 = string2;
  474. X    }
  475. X  else
  476. X    {
  477. X      end_match_1 = end1;
  478. X      end_match_2 = string2 + mstop - size1;
  479. X    }
  480. X
  481. X  /* `p' scans through the pattern as `d' scans through the data. `dend'
  482. X     is the end of the input string that `d' points within. `d' is
  483. X     advanced into the following input string whenever necessary, but
  484. X     this happens before fetching; therefore, at the beginning of the
  485. X     loop, `d' can be pointing at the end of a string, but it cannot
  486. X     equal string2.  */
  487. X
  488. X  if (size1 != 0 && pos <= size1)
  489. X    d = string1 + pos, dend = end_match_1;
  490. X  else
  491. X    d = string2 + pos - size1, dend = end_match_2;
  492. X
  493. X
  494. X  /* This loops over pattern commands.  It exits by returning from the
  495. X     function if match is complete, or it drops through if match fails
  496. X     at this starting point in the input data.  */
  497. X
  498. X  while (1)
  499. X    {
  500. X      is_a_jump_n = 0;
  501. X      /* End of pattern means we might have succeeded.  */
  502. X      if (p == pend)
  503. X    {
  504. X      /* If not end of string, try backtracking.  Otherwise done.  */
  505. X          if (d != end_match_2)
  506. X        {
  507. X              if (stackp != stackb)
  508. X                {
  509. X                  /* More failure points to try.  */
  510. X
  511. X                  unsigned in_same_string = 
  512. X                          IS_IN_FIRST_STRING (best_regend[0]) 
  513. X                        == MATCHING_IN_FIRST_STRING;
  514. X
  515. X                  /* If exceeds best match so far, save it.  */
  516. X                  if (! best_regs_set
  517. X                      || (in_same_string && d > best_regend[0])
  518. X                      || (! in_same_string && ! MATCHING_IN_FIRST_STRING))
  519. X                    {
  520. X                      best_regs_set = 1;
  521. X                      best_regend[0] = d;    /* Never use regstart[0].  */
  522. X                      
  523. X                      for (mcnt = 1; mcnt < RE_NREGS; mcnt++)
  524. X                        {
  525. X                          best_regstart[mcnt] = regstart[mcnt];
  526. X                          best_regend[mcnt] = regend[mcnt];
  527. X                        }
  528. X                    }
  529. X                  goto fail;           
  530. X                }
  531. X              /* If no failure points, don't restore garbage.  */
  532. X              else if (best_regs_set)   
  533. X                {
  534. X          restore_best_regs:
  535. X                  /* Restore best match.  */
  536. X                  d = best_regend[0];
  537. X                  
  538. X          for (mcnt = 0; mcnt < RE_NREGS; mcnt++)
  539. X            {
  540. X              regstart[mcnt] = best_regstart[mcnt];
  541. X              regend[mcnt] = best_regend[mcnt];
  542. X            }
  543. X                }
  544. X            }
  545. X
  546. X      /* If caller wants register contents data back, convert it 
  547. X         to indices.  */
  548. X      if (regs)
  549. X        {
  550. X          regs->start[0] = pos;
  551. X          if (MATCHING_IN_FIRST_STRING)
  552. X        regs->end[0] = d - string1;
  553. X          else
  554. X        regs->end[0] = d - string2 + size1;
  555. X          for (mcnt = 1; mcnt < RE_NREGS; mcnt++)
  556. X        {
  557. X          if (regend[mcnt] == (unsigned char *) -1)
  558. X            {
  559. X              regs->start[mcnt] = -1;
  560. X              regs->end[mcnt] = -1;
  561. X              continue;
  562. X            }
  563. X          if (IS_IN_FIRST_STRING (regstart[mcnt]))
  564. X            regs->start[mcnt] = regstart[mcnt] - string1;
  565. X          else
  566. X            regs->start[mcnt] = regstart[mcnt] - string2 + size1;
  567. X                    
  568. X          if (IS_IN_FIRST_STRING (regend[mcnt]))
  569. X            regs->end[mcnt] = regend[mcnt] - string1;
  570. X          else
  571. X            regs->end[mcnt] = regend[mcnt] - string2 + size1;
  572. X        }
  573. X        }
  574. X      return d - pos - (MATCHING_IN_FIRST_STRING 
  575. X                ? string1 
  576. X                : string2 - size1);
  577. X        }
  578. X
  579. X      /* Otherwise match next pattern command.  */
  580. X#ifdef SWITCH_ENUM_BUG
  581. X      switch ((int) ((enum regexpcode) *p++))
  582. X#else
  583. X      switch ((enum regexpcode) *p++)
  584. X#endif
  585. X    {
  586. X
  587. X    /* \( [or `(', as appropriate] is represented by start_memory,
  588. X           \) by stop_memory.  Both of those commands are followed by
  589. X           a register number in the next byte.  The text matched
  590. X           within the \( and \) is recorded under that number.  */
  591. X    case start_memory:
  592. X          regstart[*p] = d;
  593. X          IS_ACTIVE (reg_info[*p]) = 1;
  594. X          MATCHED_SOMETHING (reg_info[*p]) = 0;
  595. X          p++;
  596. X          break;
  597. X
  598. X    case stop_memory:
  599. X          regend[*p] = d;
  600. X          IS_ACTIVE (reg_info[*p]) = 0;
  601. X
  602. X          /* If just failed to match something this time around with a sub-
  603. X         expression that's in a loop, try to force exit from the loop.  */
  604. X          if ((! MATCHED_SOMETHING (reg_info[*p])
  605. X           || (enum regexpcode) p[-3] == start_memory)
  606. X          && (p + 1) != pend)              
  607. X            {
  608. X          register unsigned char *p2 = p + 1;
  609. X              mcnt = 0;
  610. X              switch (*p2++)
  611. X                {
  612. X                  case jump_n:
  613. X            is_a_jump_n = 1;
  614. X                  case finalize_jump:
  615. X          case maybe_finalize_jump:
  616. X          case jump:
  617. X          case dummy_failure_jump:
  618. X                    EXTRACT_NUMBER_AND_INCR (mcnt, p2);
  619. X            if (is_a_jump_n)
  620. X              p2 += 2;
  621. X                    break;
  622. X                }
  623. X          p2 += mcnt;
  624. X        
  625. X              /* If the next operation is a jump backwards in the pattern
  626. X             to an on_failure_jump, exit from the loop by forcing a
  627. X                 failure after pushing on the stack the on_failure_jump's 
  628. X                 jump in the pattern, and d.  */
  629. X          if (mcnt < 0 && (enum regexpcode) *p2++ == on_failure_jump)
  630. X        {
  631. X                  EXTRACT_NUMBER_AND_INCR (mcnt, p2);
  632. X                  PUSH_FAILURE_POINT (p2 + mcnt, d);
  633. X                  goto fail;
  634. X                }
  635. X            }
  636. X          p++;
  637. X          break;
  638. X
  639. X    /* \<digit> has been turned into a `duplicate' command which is
  640. X           followed by the numeric value of <digit> as the register number.  */
  641. X        case duplicate:
  642. X      {
  643. X        int regno = *p++;   /* Get which register to match against */
  644. X        register unsigned char *d2, *dend2;
  645. X
  646. X        /* Where in input to try to start matching.  */
  647. X            d2 = regstart[regno];
  648. X            
  649. X            /* Where to stop matching; if both the place to start and
  650. X               the place to stop matching are in the same string, then
  651. X               set to the place to stop, otherwise, for now have to use
  652. X               the end of the first string.  */
  653. X
  654. X            dend2 = ((IS_IN_FIRST_STRING (regstart[regno]) 
  655. X              == IS_IN_FIRST_STRING (regend[regno]))
  656. X             ? regend[regno] : end_match_1);
  657. X        while (1)
  658. X          {
  659. X        /* If necessary, advance to next segment in register
  660. X                   contents.  */
  661. X        while (d2 == dend2)
  662. X          {
  663. X            if (dend2 == end_match_2) break;
  664. X            if (dend2 == regend[regno]) break;
  665. X            d2 = string2, dend2 = regend[regno];  /* end of string1 => advance to string2. */
  666. X          }
  667. X        /* At end of register contents => success */
  668. X        if (d2 == dend2) break;
  669. X
  670. X        /* If necessary, advance to next segment in data.  */
  671. X        PREFETCH;
  672. X
  673. X        /* How many characters left in this segment to match.  */
  674. X        mcnt = dend - d;
  675. X                
  676. X        /* Want how many consecutive characters we can match in
  677. X                   one shot, so, if necessary, adjust the count.  */
  678. X                if (mcnt > dend2 - d2)
  679. X          mcnt = dend2 - d2;
  680. X                  
  681. X        /* Compare that many; failure if mismatch, else move
  682. X                   past them.  */
  683. X        if (translate 
  684. X                    ? bcmp_translate (d, d2, mcnt, translate) 
  685. X                    : bcmp (d, d2, mcnt))
  686. X          goto fail;
  687. X        d += mcnt, d2 += mcnt;
  688. X          }
  689. X      }
  690. X      break;
  691. X
  692. X    case anychar:
  693. X      PREFETCH;      /* Fetch a data character. */
  694. X      /* Match anything but a newline, maybe even a null.  */
  695. X      if ((translate ? translate[*d] : *d) == '\n'
  696. X              || ((obscure_syntax & RE_DOT_NOT_NULL) 
  697. X                  && (translate ? translate[*d] : *d) == '\000'))
  698. X        goto fail;
  699. X      SET_REGS_MATCHED;
  700. X          d++;
  701. X      break;
  702. X
  703. X    case charset:
  704. X    case charset_not:
  705. X      {
  706. X        int not = 0;        /* Nonzero for charset_not.  */
  707. X        register int c;
  708. X        if (*(p - 1) == (unsigned char) charset_not)
  709. X          not = 1;
  710. X
  711. X        PREFETCH;        /* Fetch a data character. */
  712. X
  713. X        if (translate)
  714. X          c = translate[*d];
  715. X        else
  716. X          c = *d;
  717. X
  718. X        if (c < *p * BYTEWIDTH
  719. X        && p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
  720. X          not = !not;
  721. X
  722. X        p += 1 + *p;
  723. X
  724. X        if (!not) goto fail;
  725. X        SET_REGS_MATCHED;
  726. X            d++;
  727. X        break;
  728. X      }
  729. X
  730. X    case begline:
  731. X          if ((size1 != 0 && d == string1)
  732. X              || (size1 == 0 && size2 != 0 && d == string2)
  733. X              || (d && d[-1] == '\n')
  734. X              || (size1 == 0 && size2 == 0))
  735. X            break;
  736. X          else
  737. X            goto fail;
  738. X            
  739. X    case endline:
  740. X      if (d == end2
  741. X          || (d == end1 ? (size2 == 0 || *string2 == '\n') : *d == '\n'))
  742. X        break;
  743. X      goto fail;
  744. X
  745. X    /* `or' constructs are handled by starting each alternative with
  746. X           an on_failure_jump that points to the start of the next
  747. X           alternative.  Each alternative except the last ends with a
  748. X           jump to the joining point.  (Actually, each jump except for
  749. X           the last one really jumps to the following jump, because
  750. X           tensioning the jumps is a hassle.)  */
  751. X
  752. X    /* The start of a stupid repeat has an on_failure_jump that points
  753. X       past the end of the repeat text. This makes a failure point so 
  754. X           that on failure to match a repetition, matching restarts past
  755. X           as many repetitions have been found with no way to fail and
  756. X           look for another one.  */
  757. X
  758. X    /* A smart repeat is similar but loops back to the on_failure_jump
  759. X       so that each repetition makes another failure point.  */
  760. X
  761. X    case on_failure_jump:
  762. X        on_failure:
  763. X          EXTRACT_NUMBER_AND_INCR (mcnt, p);
  764. X          PUSH_FAILURE_POINT (p + mcnt, d);
  765. X          break;
  766. X
  767. X    /* The end of a smart repeat has a maybe_finalize_jump back.
  768. X       Change it either to a finalize_jump or an ordinary jump.  */
  769. X    case maybe_finalize_jump:
  770. X          EXTRACT_NUMBER_AND_INCR (mcnt, p);
  771. X      {
  772. X        register unsigned char *p2 = p;
  773. X        /* Compare what follows with the beginning of the repeat.
  774. X           If we can establish that there is nothing that they would
  775. X           both match, we can change to finalize_jump.  */
  776. X        while (p2 + 1 != pend
  777. X           && (*p2 == (unsigned char) stop_memory
  778. X               || *p2 == (unsigned char) start_memory))
  779. X          p2 += 2;                /* Skip over reg number.  */
  780. X        if (p2 == pend)
  781. X          p[-3] = (unsigned char) finalize_jump;
  782. X        else if (*p2 == (unsigned char) exactn
  783. X             || *p2 == (unsigned char) endline)
  784. X          {
  785. X        register int c = *p2 == (unsigned char) endline ? '\n' : p2[2];
  786. X        register unsigned char *p1 = p + mcnt;
  787. X        /* p1[0] ... p1[2] are an on_failure_jump.
  788. X           Examine what follows that.  */
  789. X        if (p1[3] == (unsigned char) exactn && p1[5] != c)
  790. X          p[-3] = (unsigned char) finalize_jump;
  791. X        else if (p1[3] == (unsigned char) charset
  792. X             || p1[3] == (unsigned char) charset_not)
  793. X          {
  794. X            int not = p1[3] == (unsigned char) charset_not;
  795. X            if (c < p1[4] * BYTEWIDTH
  796. X            && p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
  797. X              not = !not;
  798. X            /* `not' is 1 if c would match.  */
  799. X            /* That means it is not safe to finalize.  */
  800. X            if (!not)
  801. X              p[-3] = (unsigned char) finalize_jump;
  802. X          }
  803. X          }
  804. X      }
  805. X      p -= 2;        /* Point at relative address again.  */
  806. X      if (p[-1] != (unsigned char) finalize_jump)
  807. X        {
  808. X          p[-1] = (unsigned char) jump;    
  809. X          goto nofinalize;
  810. X        }
  811. X        /* Note fall through.  */
  812. X
  813. X    /* The end of a stupid repeat has a finalize_jump back to the
  814. X           start, where another failure point will be made which will
  815. X           point to after all the repetitions found so far.  */
  816. X
  817. X        /* Take off failure points put on by matching on_failure_jump 
  818. X           because didn't fail.  Also remove the register information
  819. X           put on by the on_failure_jump.  */
  820. X        case finalize_jump:
  821. X          POP_FAILURE_POINT ();
  822. X        /* Note fall through.  */
  823. X        
  824. X    /* Jump without taking off any failure points.  */
  825. X        case jump:
  826. X    nofinalize:
  827. X      EXTRACT_NUMBER_AND_INCR (mcnt, p);
  828. X      p += mcnt;
  829. X      break;
  830. X
  831. X        case dummy_failure_jump:
  832. X          /* Normally, the on_failure_jump pushes a failure point, which
  833. X             then gets popped at finalize_jump.  We will end up at
  834. X             finalize_jump, also, and with a pattern of, say, `a+', we
  835. X             are skipping over the on_failure_jump, so we have to push
  836. X             something meaningless for finalize_jump to pop.  */
  837. X          PUSH_FAILURE_POINT (0, 0);
  838. X          goto nofinalize;
  839. X
  840. X
  841. X        /* Have to succeed matching what follows at least n times.  Then
  842. X          just handle like an on_failure_jump.  */
  843. X        case succeed_n: 
  844. X          EXTRACT_NUMBER (mcnt, p + 2);
  845. X          /* Originally, this is how many times we HAVE to succeed.  */
  846. X          if (mcnt)
  847. X            {
  848. X               mcnt--;
  849. X           p += 2;
  850. X               STORE_NUMBER_AND_INCR (p, mcnt);
  851. X            }
  852. X      else if (mcnt == 0)
  853. X            {
  854. X          p[2] = unused;
  855. X              p[3] = unused;
  856. X              goto on_failure;
  857. X            }
  858. X          else
  859. X        { 
  860. X              fprintf (stderr, "regex: the succeed_n's n is not set.\n");
  861. X              exit (1);
  862. X        }
  863. X          break;
  864. X        
  865. X        case jump_n: 
  866. X          EXTRACT_NUMBER (mcnt, p + 2);
  867. X          /* Originally, this is how many times we CAN jump.  */
  868. X          if (mcnt)
  869. X            {
  870. X               mcnt--;
  871. X               STORE_NUMBER(p + 2, mcnt);
  872. X           goto nofinalize;         /* Do the jump without taking off
  873. X                            any failure points.  */
  874. X            }
  875. X          /* If don't have to jump any more, skip over the rest of command.  */
  876. X      else      
  877. X        p += 4;             
  878. X          break;
  879. X        
  880. X    case set_number_at:
  881. X      {
  882. X          register unsigned char *p1;
  883. X
  884. X            EXTRACT_NUMBER_AND_INCR (mcnt, p);
  885. X            p1 = p + mcnt;
  886. X            EXTRACT_NUMBER_AND_INCR (mcnt, p);
  887. X        STORE_NUMBER (p1, mcnt);
  888. X            break;
  889. X          }
  890. X
  891. X        /* Ignore these.  Used to ignore the n of succeed_n's which
  892. X           currently have n == 0.  */
  893. X        case unused:
  894. X          break;
  895. X
  896. X        case wordbound:
  897. X      if (AT_WORD_BOUNDARY)
  898. X        break;
  899. X      goto fail;
  900. X
  901. X    case notwordbound:
  902. X      if (AT_WORD_BOUNDARY)
  903. X        goto fail;
  904. X      break;
  905. X
  906. X    case wordbeg:
  907. X      if (IS_A_LETTER (d) && (!IS_A_LETTER (d - 1) || AT_STRINGS_BEG))
  908. X        break;
  909. X      goto fail;
  910. X
  911. X    case wordend:
  912. X          /* Have to check if AT_STRINGS_BEG before looking at d - 1.  */
  913. X      if (!AT_STRINGS_BEG && IS_A_LETTER (d - 1) 
  914. X              && (!IS_A_LETTER (d) || AT_STRINGS_END))
  915. X        break;
  916. X      goto fail;
  917. X
  918. X#ifdef emacs
  919. X    case before_dot:
  920. X      if (PTR_CHAR_POS (d) >= point)
  921. X        goto fail;
  922. X      break;
  923. X
  924. X    case at_dot:
  925. X      if (PTR_CHAR_POS (d) != point)
  926. X        goto fail;
  927. X      break;
  928. X
  929. X    case after_dot:
  930. X      if (PTR_CHAR_POS (d) <= point)
  931. X        goto fail;
  932. X      break;
  933. X
  934. X    case wordchar:
  935. X      mcnt = (int) Sword;
  936. X      goto matchsyntax;
  937. X
  938. X    case syntaxspec:
  939. X      mcnt = *p++;
  940. X    matchsyntax:
  941. X      PREFETCH;
  942. X      if (SYNTAX (*d++) != (enum syntaxcode) mcnt) goto fail;
  943. X          SET_REGS_MATCHED;
  944. X      break;
  945. X      
  946. X    case notwordchar:
  947. X      mcnt = (int) Sword;
  948. X      goto matchnotsyntax;
  949. X
  950. X    case notsyntaxspec:
  951. X      mcnt = *p++;
  952. X    matchnotsyntax:
  953. X      PREFETCH;
  954. X      if (SYNTAX (*d++) == (enum syntaxcode) mcnt) goto fail;
  955. X      SET_REGS_MATCHED;
  956. X          break;
  957. X
  958. X#else /* not emacs */
  959. X
  960. X    case wordchar:
  961. X      PREFETCH;
  962. X          if (!IS_A_LETTER (d))
  963. X            goto fail;
  964. X      SET_REGS_MATCHED;
  965. X      break;
  966. X      
  967. X    case notwordchar:
  968. X      PREFETCH;
  969. X      if (IS_A_LETTER (d))
  970. X            goto fail;
  971. X          SET_REGS_MATCHED;
  972. X      break;
  973. X
  974. X#endif /* not emacs */
  975. X
  976. X    case begbuf:
  977. X          if (AT_STRINGS_BEG)
  978. X            break;
  979. X          goto fail;
  980. X
  981. X        case endbuf:
  982. X      if (AT_STRINGS_END)
  983. X        break;
  984. X      goto fail;
  985. X
  986. X    case exactn:
  987. X      /* Match the next few pattern characters exactly.
  988. X         mcnt is how many characters to match.  */
  989. X      mcnt = *p++;
  990. X      /* This is written out as an if-else so we don't waste time
  991. X             testing `translate' inside the loop.  */
  992. X          if (translate)
  993. X        {
  994. X          do
  995. X        {
  996. X          PREFETCH;
  997. X          if (translate[*d++] != *p++) goto fail;
  998. X        }
  999. X          while (--mcnt);
  1000. X        }
  1001. X      else
  1002. X        {
  1003. X          do
  1004. X        {
  1005. X          PREFETCH;
  1006. X          if (*d++ != *p++) goto fail;
  1007. X        }
  1008. X          while (--mcnt);
  1009. X        }
  1010. X      SET_REGS_MATCHED;
  1011. X          break;
  1012. X    }
  1013. X      continue;  /* Successfully executed one pattern command; keep going.  */
  1014. X
  1015. X    /* Jump here if any matching operation fails. */
  1016. X    fail:
  1017. X      if (stackp != stackb)
  1018. X    /* A restart point is known.  Restart there and pop it. */
  1019. X    {
  1020. X          short last_used_reg, this_reg;
  1021. X          
  1022. X          /* If this failure point is from a dummy_failure_point, just
  1023. X             skip it.  */
  1024. X      if (!stackp[-2])
  1025. X            {
  1026. X              POP_FAILURE_POINT ();
  1027. X              goto fail;
  1028. X            }
  1029. X
  1030. X          d = *--stackp;
  1031. X      p = *--stackp;
  1032. X          if (d >= string1 && d <= end1)
  1033. X        dend = end_match_1;
  1034. X          /* Restore register info.  */
  1035. X          last_used_reg = (short) *--stackp;
  1036. X          
  1037. X          /* Make the ones that weren't saved -1 or 0 again.  */
  1038. X          for (this_reg = RE_NREGS - 1; this_reg > last_used_reg; this_reg--)
  1039. X            {
  1040. X              regend[this_reg] = (unsigned char *) -1;
  1041. X              regstart[this_reg] = (unsigned char *) -1;
  1042. X              IS_ACTIVE (reg_info[this_reg]) = 0;
  1043. X              MATCHED_SOMETHING (reg_info[this_reg]) = 0;
  1044. X            }
  1045. X          
  1046. X          /* And restore the rest from the stack.  */
  1047. X          for ( ; this_reg > 0; this_reg--)
  1048. X            {
  1049. X              reg_info[this_reg] = *(struct register_info *) *--stackp;
  1050. X              regend[this_reg] = *--stackp;
  1051. X              regstart[this_reg] = *--stackp;
  1052. X            }
  1053. X    }
  1054. X      else
  1055. X        break;   /* Matching at this starting point really fails.  */
  1056. X    }
  1057. X
  1058. X  if (best_regs_set)
  1059. X    goto restore_best_regs;
  1060. X  return -1;                     /* Failure to match.  */
  1061. X}
  1062. X
  1063. X
  1064. Xstatic int
  1065. Xbcmp_translate (s1, s2, len, translate)
  1066. X     unsigned char *s1, *s2;
  1067. X     register int len;
  1068. X     unsigned char *translate;
  1069. X{
  1070. X  register unsigned char *p1 = s1, *p2 = s2;
  1071. X  while (len)
  1072. X    {
  1073. X      if (translate [*p1++] != translate [*p2++]) return 1;
  1074. X      len--;
  1075. X    }
  1076. X  return 0;
  1077. X}
  1078. X
  1079. X
  1080. X
  1081. X/* Entry points compatible with 4.2 BSD regex library.  */
  1082. X
  1083. X#ifndef emacs
  1084. X
  1085. Xstatic struct re_pattern_buffer re_comp_buf;
  1086. X
  1087. Xchar *
  1088. Xre_comp (s)
  1089. X     char *s;
  1090. X{
  1091. X  if (!s)
  1092. X    {
  1093. X      if (!re_comp_buf.buffer)
  1094. X    return "No previous regular expression";
  1095. X      return 0;
  1096. X    }
  1097. X
  1098. X  if (!re_comp_buf.buffer)
  1099. X    {
  1100. X      if (!(re_comp_buf.buffer = (char *) malloc (200)))
  1101. X    return "Memory exhausted";
  1102. X      re_comp_buf.allocated = 200;
  1103. X      if (!(re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH)))
  1104. X    return "Memory exhausted";
  1105. X    }
  1106. X  return re_compile_pattern (s, strlen (s), &re_comp_buf);
  1107. X}
  1108. X
  1109. Xint
  1110. Xre_exec (s)
  1111. X     char *s;
  1112. X{
  1113. X  int len = strlen (s);
  1114. X  return 0 <= re_search (&re_comp_buf, s, len, 0, len,
  1115. X             (struct re_registers *) 0);
  1116. X}
  1117. X#endif /* not emacs */
  1118. X
  1119. X
  1120. X
  1121. X#ifdef test
  1122. X
  1123. X#include <stdio.h>
  1124. X
  1125. X/* Indexed by a character, gives the upper case equivalent of the
  1126. X   character.  */
  1127. X
  1128. Xchar upcase[0400] = 
  1129. X  { 000, 001, 002, 003, 004, 005, 006, 007,
  1130. X    010, 011, 012, 013, 014, 015, 016, 017,
  1131. X    020, 021, 022, 023, 024, 025, 026, 027,
  1132. X    030, 031, 032, 033, 034, 035, 036, 037,
  1133. X    040, 041, 042, 043, 044, 045, 046, 047,
  1134. X    050, 051, 052, 053, 054, 055, 056, 057,
  1135. X    060, 061, 062, 063, 064, 065, 066, 067,
  1136. X    070, 071, 072, 073, 074, 075, 076, 077,
  1137. X    0100, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
  1138. X    0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117,
  1139. X    0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127,
  1140. X    0130, 0131, 0132, 0133, 0134, 0135, 0136, 0137,
  1141. X    0140, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
  1142. X    0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117,
  1143. X    0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127,
  1144. X    0130, 0131, 0132, 0173, 0174, 0175, 0176, 0177,
  1145. X    0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207,
  1146. X    0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217,
  1147. X    0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227,
  1148. X    0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237,
  1149. X    0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247,
  1150. X    0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
  1151. X    0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
  1152. X    0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
  1153. X    0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
  1154. X    0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317,
  1155. X    0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327,
  1156. X    0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
  1157. X    0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
  1158. X    0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357,
  1159. X    0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
  1160. X    0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377
  1161. X  };
  1162. X
  1163. X#ifdef canned
  1164. X
  1165. X#include "tests.h"
  1166. X
  1167. Xtypedef enum { extended_test, basic_test } test_type;
  1168. X
  1169. X/* Use this to run the tests we've thought of.  */
  1170. X
  1171. Xvoid
  1172. Xmain ()
  1173. X{
  1174. X  test_type t = extended_test;
  1175. X
  1176. X  if (t == basic_test)
  1177. X    {
  1178. X      printf ("Running basic tests:\n\n");
  1179. X      test_posix_basic ();
  1180. X    }
  1181. X  else if (t == extended_test)
  1182. X    {
  1183. X      printf ("Running extended tests:\n\n");
  1184. X      test_posix_extended (); 
  1185. X    }
  1186. X}
  1187. X
  1188. X#else /* not canned */
  1189. X
  1190. X/* Use this to run interactive tests.  */
  1191. X
  1192. Xvoid
  1193. Xmain (argc, argv)
  1194. X     int argc;
  1195. X     char **argv;
  1196. X{
  1197. X  char pat[80];
  1198. X  struct re_pattern_buffer buf;
  1199. X  int i;
  1200. X  char c;
  1201. X  char fastmap[(1 << BYTEWIDTH)];
  1202. X
  1203. X  /* Allow a command argument to specify the style of syntax.  */
  1204. X  if (argc > 1)
  1205. X    obscure_syntax = atoi (argv[1]);
  1206. X
  1207. X  buf.allocated = 40;
  1208. X  buf.buffer = (char *) malloc (buf.allocated);
  1209. X  buf.fastmap = fastmap;
  1210. X  buf.translate = upcase;
  1211. X
  1212. X  while (1)
  1213. X    {
  1214. X      gets (pat);
  1215. X
  1216. X      if (*pat)
  1217. X    {
  1218. X          re_compile_pattern (pat, strlen(pat), &buf);
  1219. X
  1220. X      for (i = 0; i < buf.used; i++)
  1221. X        printchar (buf.buffer[i]);
  1222. X
  1223. X      putchar ('\n');
  1224. X
  1225. X      printf ("%d allocated, %d used.\n", buf.allocated, buf.used);
  1226. X
  1227. X      re_compile_fastmap (&buf);
  1228. X      printf ("Allowed by fastmap: ");
  1229. X      for (i = 0; i < (1 << BYTEWIDTH); i++)
  1230. X        if (fastmap[i]) printchar (i);
  1231. X      putchar ('\n');
  1232. X    }
  1233. X
  1234. X      gets (pat);    /* Now read the string to match against */
  1235. X
  1236. X      i = re_match (&buf, pat, strlen (pat), 0, 0);
  1237. X      printf ("Match value %d.\n", i);
  1238. X    }
  1239. X}
  1240. X
  1241. X#endif
  1242. X
  1243. X
  1244. X#ifdef NOTDEF
  1245. Xprint_buf (bufp)
  1246. X     struct re_pattern_buffer *bufp;
  1247. X{
  1248. X  int i;
  1249. X
  1250. X  printf ("buf is :\n----------------\n");
  1251. X  for (i = 0; i < bufp->used; i++)
  1252. X    printchar (bufp->buffer[i]);
  1253. X  
  1254. X  printf ("\n%d allocated, %d used.\n", bufp->allocated, bufp->used);
  1255. X  
  1256. X  printf ("Allowed by fastmap: ");
  1257. X  for (i = 0; i < (1 << BYTEWIDTH); i++)
  1258. X    if (bufp->fastmap[i])
  1259. X      printchar (i);
  1260. X  printf ("\nAllowed by translate: ");
  1261. X  if (bufp->translate)
  1262. X    for (i = 0; i < (1 << BYTEWIDTH); i++)
  1263. X      if (bufp->translate[i])
  1264. X    printchar (i);
  1265. X  printf ("\nfastmap is%s accurate\n", bufp->fastmap_accurate ? "" : "n't");
  1266. X  printf ("can %s be null\n----------", bufp->can_be_null ? "" : "not");
  1267. X}
  1268. X#endif /* NOTDEF */
  1269. X
  1270. Xprintchar (c)
  1271. X     char c;
  1272. X{
  1273. X  if (c < 040 || c >= 0177)
  1274. X    {
  1275. X      putchar ('\\');
  1276. X      putchar (((c >> 6) & 3) + '0');
  1277. X      putchar (((c >> 3) & 7) + '0');
  1278. X      putchar ((c & 7) + '0');
  1279. X    }
  1280. X  else
  1281. X    putchar (c);
  1282. X}
  1283. X
  1284. Xerror (string)
  1285. X     char *string;
  1286. X{
  1287. X  puts (string);
  1288. X  exit (1);
  1289. X}
  1290. X#endif /* test */
  1291. END_OF_FILE
  1292. if test 37881 -ne `wc -c <'regex.c2'`; then
  1293.     echo shar: \"'regex.c2'\" unpacked with wrong size!
  1294. fi
  1295. # end of 'regex.c2'
  1296. fi
  1297. if test -r regex.c1 -a -r regex.c2
  1298. then
  1299.     echo shar: concatenating \"regex.c1\" and \"regex.c2\" into \"regex.c\"
  1300.     cat regex.c1 regex.c2 >regex.c || echo shar: \"regex.c\" creation failed!
  1301. fi
  1302. echo shar: End of archive 6 \(of 8\).
  1303. cp /dev/null ark6isdone
  1304. MISSING=""
  1305. for I in 1 2 3 4 5 6 7 8 ; do
  1306.     if test ! -f ark${I}isdone ; then
  1307.     MISSING="${MISSING} ${I}"
  1308.     fi
  1309. done
  1310. if test "${MISSING}" = "" ; then
  1311.     echo You have unpacked all 8 archives.
  1312.     rm -f ark[1-9]isdone
  1313. else
  1314.     echo You still need to unpack the following archives:
  1315.     echo "        " ${MISSING}
  1316. fi
  1317. ##  End of shell archive.
  1318. exit 0
  1319.  
  1320. exit 0 # Just in case...
  1321.